package com.ruixin.parser;

import com.ruixin.base.BaseParser;
import com.ruixin.base.ParseType;
import com.ruixin.base.exception.BaseException;
import com.ruixin.base.util.BeanUtil;
import com.ruixin.config.ApplicationContext;
import com.ruixin.config.ClassLoader;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Set;

/**
 * 默认的类加载
 */
public class ClassParser extends BaseParser<ApplicationContext> {

    public ClassParser(ApplicationContext context, Class<? extends Annotation> type) {
        super(context, type);
    }

    /**
     * 解析所有的类
     * @throws BaseException
     */
    public void init() throws BaseException {
        ClassLoader classLoader = this.context.getClassLoader();
        //处理Parser类型
        Set<Class<?>> parserClasses = classLoader.getParserClasses();
        parseClass(parserClasses,ParseType.PARSE_TYPE_Class);
        //处理Bean
        Set<Class<?>> beanClasses = classLoader.getBeanClasses();
        parseClass(beanClasses,ParseType.PARSE_TYPE_Class);
        //处理Field
        parseClass(parserClasses,ParseType.PARSE_TYPE_Field);
        parseClass(beanClasses,ParseType.PARSE_TYPE_Field);

        //处理Method
        parseClass(beanClasses,ParseType.PARSE_TYPE_Method);
    }

    /**
     * 批量处理类
     * @param classes
     * @throws BaseException
     */
    public void parseClass(Set<Class<?>> classes, ParseType parseType) throws BaseException {
        for (Class<?> beanClass : classes) {
            switch (parseType){
                case PARSE_TYPE_Class:parseClass(beanClass);break;
                case PARSE_TYPE_Field:
                    Object bean = this.context.getBean(beanClass);
                    Field[] fields = beanClass.getDeclaredFields();
                    for (Field field : fields) {
                        field.setAccessible(true);
                        parseField(bean,field);
                    }
                    break;
                case PARSE_TYPE_Method:
                    Object beanObj = this.context.getBean(beanClass);
                    Method[] methods = beanClass.getDeclaredMethods();
                    for (Method method : methods) {
                        parseMethod(beanObj,method);
                    }
                    break;
                case PARSE_TYPE_Parameter:
                    break;
            }
        }
    }

    @Override
    public void parseClass(Class<?> clz) throws BaseException {
        List<Annotation> annotations = BeanUtil.getAnnotations(clz);
        for (Annotation annotation : annotations) {
            BaseParser<ApplicationContext> parser = this.context.getAnnotationParser(annotation.annotationType());
            parser.parseClass(clz);
        }
    }


    @Override
    public void parseField(Object bean, Field field) throws BaseException {
        super.parseField(bean, field);
        List<Annotation> annotations = BeanUtil.getAnnotations(field);
        for (Annotation annotation : annotations) {
            BaseParser<ApplicationContext> parser = this.context.getAnnotationParser(annotation.annotationType());
            parser.parseField(bean,field);
        }
    }

    @Override
    public void parseMethod(Object bean, Method method) throws BaseException {
        super.parseMethod(bean, method);
        List<Annotation> annotations = BeanUtil.getAnnotations(method);
        for (Annotation annotation : annotations) {
            BaseParser<ApplicationContext> parser = this.context.getAnnotationParser(annotation.annotationType());
            parser.parseMethod(bean,method);
        }
        Parameter[] parameters = method.getParameters();
        for (Parameter parameter : parameters) {
            this.parseParamater(bean,method,parameter);
        }
    }

    @Override
    public void parseParamater(Object bean, Method method, Parameter parameter) throws BaseException {
        super.parseParamater(bean, method, parameter);
        List<Annotation> annotations = BeanUtil.getAnnotations(parameter);
        for (Annotation annotation : annotations) {
            BaseParser<ApplicationContext> parser = this.context.getAnnotationParser(annotation.annotationType());
            parser.parseParamater(bean,method,parameter);
        }
    }

    /**
     * 必须要存在注解
     * @param obj
     * @return
     * @throws BaseException
     */
    @Override
    public boolean isValid(Object obj) throws BaseException {
        return true;
    }

}
